package com.lottery.material.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * Description：Java Calendar 类时间操作：获取时间，时间加减，以及比较时间大小等等。
 * Created by 朱正磊 on 2017-02-20 11:53.
 */
@SuppressWarnings("ALL")
@Slf4j
public class CalendarUtil {

	/**
	 * @Desc 显示年份
	 * @return
	 */
	public static int getYear(){
		return Calendar.getInstance().get(Calendar.YEAR);
	}

	/**
	 * @Desc 显示月份 (从0开始, 实际显示要加1)
	 * @return
	 */
	public static int getMonth(){
		return Calendar.getInstance().get(Calendar.MONTH) + 1;
	}

	/**
	 * @Desc 本月的第几天
	 * @return
	 */
	public static int getDayOfMonth(){
		return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * @Desc 本周几（星期几，礼拜几）
	 * @return
	 */
	public static String getDayOfWeek(){
		int dayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
		String day = "";
		switch (dayOfWeek){//int，short，char，byte
			case 1:
				day = "SUNDAY";//星期天（星期日）
				break;
			case 2:
				day = "MONDAY";//星期一
				break;
			case 3:
				day = "TUESDAY";//星期二
				break;
			case 4:
				day = "WEDNESDAY";//星期三
				break;
			case 5:
				day = "THURSDAY";//星期四
				break;
			case 6:
				day = "FRIDAY";//星期五
				break;
			default:
				day = "SATURDAY";//星期六
		}
		return day;
	}

	/**
	 * @Desc 今年的第几天
	 * @return
	 */
	public static int getDayOfYear(){
		return Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * @Desc 获取小时数
	 * @return
	 */
	public static int getHour(){
		return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @Desc n小时以后（获取的是小时，比如现在是18点，那么该方法就返回18+n点）
	 * @param n
	 * @return
	 */
	public static int getHourOfDayAfterN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, n);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @Desc n小时以前（获取的是小时，比如现在是18点，那么该方法就返回18-n点）
	 * @param n
	 * @return
	 */
	public static int getHourOfDayBeforeN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, unm(n));
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * @Desc 获取分钟数
	 * @return
	 */
	public static int getMinute(){
		return Calendar.getInstance().get(Calendar.MINUTE);
	}

	/**
	 * @Desc n分钟以后（比如现在是38分，那么10分钟以后就是48分）
	 * @param n
	 * @return
	 */
	public static int getMinuteAfterN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, n);
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * @Desc n分钟以前（比如现在是38分，那么10分钟以前就是28分）
	 * @param n
	 * @return
	 */
	public static int getMinuteBeforeN(int n){
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, unm(n));
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * @Desc 取整数的相反数
	 * @param num
	 * @return
	 */
	public static int unm(int num){
		return -num;
	}

	/**
	 * @Desc 格式化显示日期（日期转字符串）
	 * @param date
	 * @param regex 规则
	 * @return
	 */
	public static String dateToString(Date date, String regex){
		if(date != null){
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			return new SimpleDateFormat(regex).format(calendar.getTime());
		}
		return null;
	}

	/**
	 * @Desc 格式化显示日期（日期转字符串）
	 * @param date
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static String dateToString(Date date){
		return dateToString(date, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @Desc 格式化显示日期（日期转字符串）
	 * @param date
	 * @param regex 规则
	 * @return
	 */
	public static String dateToStringAnother(Date date, String regex){
		return new SimpleDateFormat(regex).format(date);
	}

	/**
	 * @Desc 显示当前时间（字符串）
	 * @param regex 规则
	 * @return
	 */
	public static String getNowDate(String regex){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());//默认就是执行此方法，可以省略不写
		return new SimpleDateFormat(regex).format(calendar.getTime());
	}

	/**
	 * @Desc 显示当前时间（字符串）
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static String getNowDate(){
		return getNowDate("yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @Desc 显示当前时间（字符串）
	 * @param regex 规则
	 * @return
	 */
	public static String getNowDateAnother(String regex){
		return new SimpleDateFormat(regex).format(new Date());
	}

	/**
	 * @Desc 获取系统当前时间，其实就是new Date();
	 * @return
	 */
	public static Date getSystemCurrentDate() {
		return Calendar.getInstance().getTime();
	}

	/**
	 * @Desc 根据日期规则将字符串转换为日期格式
	 * @param dateStr
	 * @param regex 规则（要和dateStr的格式一致）
	 * @return
	 */
	public static Date stringToDate(String dateStr, String regex){
		try {
			return new SimpleDateFormat(regex).parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
			log.info("日期格式转换异常："+dateStr+"和"+regex+"的格式不匹配");
			System.out.println("日期格式转换异常："+dateStr+"和"+regex+"的格式不匹配");
			log.error("【字符串转日期失败，异常信息为】："+ e.getMessage());
			System.out.println("【字符串转日期失败，异常信息为】："+ e.getMessage());
		}
		return null;
	}

	/**
	 * @Desc 根据日期规则将字符串转换为日期格式
	 * @param dateStr
	 * @return 缺省格式化规则默认是日期时间格式
	 */
	public static Date stringToDate(String dateStr){
		return stringToDate(dateStr, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * @Desc 在只考虑yyyy-MM-dd和yyyy-MM-dd HH:mm:ss这两种情况下使用该方法，
	 * 		 当然了如果还有其他情况可以继续写判断！
	 * @param dateStr
	 * @return
	 */
	public static Date commonToDate(String dateStr) throws Exception{
		if(dateStr.length() == 10){
			return stringToDate(dateStr, "yyyy-MM-dd");
		}else if(dateStr.length() == 19){
			return stringToDate(dateStr);
		}
		return null;
	}

	/**
	 * @Desc 计算需要的时间
	 * @param date 原时间
	 * @param month 可以为null，为正数代表加，为负数代表减
	 * @param day 可以为null，为正数代表加，为负数代表减
	 * @param hour 可以为null，为正数代表加，为负数代表减
	 * @param minute 可以为null，为正数代表加，为负数代表减
	 * @return 返回加减后的时间
	 */
	public static Date getWantedDate(Date date, Integer month, Integer day, Integer hour, Integer minute) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		if (null != month) {
			calendar.add(Calendar.MONTH, month);
		}
		if (null != day) {
			calendar.add(Calendar.DAY_OF_MONTH, day);
		}
		if (null != hour) {
			calendar.add(Calendar.HOUR_OF_DAY, hour);
		}
		if (null != minute) {
			calendar.add(Calendar.MINUTE, minute);
		}
		return calendar.getTime();
	}

	/**
	 * 说明：假如当然日期是2017-10-08，如果days为5，
	 * 那么得到的日期是2017-10-13，如果days为-5，那么得到的日期是2017-10-03
	 * @description 跟当前时间的日进行相加减获取想要的日期
	 * @param days 为正数表示延后多少天，为负数表示提前多少天
	 * @return 返回计算天数后的年月日字符串
	 */
	public static String getWantedDay(Integer days) {
		return new DateTime().plusDays(days).toString("yyyy-MM-dd");
	}
	
	/**
	 * @Desc 比较大小
	 * 后者大，显示 -1
	 * 前者大，显示 1
	 * 时间相同，显示 0
	 * @param date1 被比较时间
	 * @param date2 比较时间
	 * @return 如果被比较时间晚于比较时间返回1，否则返回-1
	 */
	public static int compare(Date date1, Date date2){
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(date1);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(date2);
		return calendar1.compareTo(calendar2);
	}

	/**
	 * @Desc 比较大小
	 * 后者大，显示 -1
	 * 前者大，显示 1
	 * 时间相同，显示 0
	 * @param date1 被比较时间
	 * @param regex1 规则
	 * @param date2 比较时间
	 * @param regex2 规则
	 * @return 如果被比较时间晚于比较时间返回1，否则返回-1
	 */
	public static int compare(String date1, String regex1, String date2, String regex2){
		Date date11 = stringToDate(date1,regex1);
		Date date22 = stringToDate(date2,regex2);
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(date11);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(date22);
		return calendar1.compareTo(calendar2);
	}

	/**
	 * @Desc 获取当前系统时间（单位：毫秒）
	 * @return
	 */
	public static long getStartTime(){
		return System.currentTimeMillis();
	}

	/**
	 * @Desc 计算系统间隔时间（单位：秒）
	 * @param startTime 系统开始时间
	 * @return
	 */
	public static long interval(long startTime){
		long endTime = System.currentTimeMillis();
		return (endTime - startTime)/1000;
	}

	/**
	 * @Desc 计算2个日期之间相隔的天数
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static int getDaysBetween(Calendar d1, Calendar d2) {
		if (d1.after(d2)) {//如果d1在d2后面，那么把两者的值进行互换，确保d2在d1的后面
			Calendar swap = d1;
			d1 = d2;
			d2 = swap;
		}
		int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
		int y2 = d2.get(Calendar.YEAR);
		if (d1.get(Calendar.YEAR) != y2) {
			d1 = (Calendar) d1.clone();
			do {
				days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);
				d1.add(Calendar.YEAR, 1);
			} while (d1.get(Calendar.YEAR) != y2);
		}
		return days;
	}

	/**
	 * @Desc 计算2个日期之间相隔的工作日天数
	 * @param d1
	 * @param d2
	 * @return
	 */
	public static int getWorkingDay(Calendar d1, Calendar d2) {
		int result ;
		if (d1.after(d2)) {//如果d1在d2后面，那么把两者的值进行互换，确保d2在d1的后面
			Calendar swap = d1;
			d1 = d2;
			d2 = swap;
		}
		int charge_start_date = 0;//开始日期的日期偏移量
		int charge_end_date = 0;//结束日期的日期偏移量
		// 日期不在同一个日期内
		int stmp;
		int etmp;
		stmp = 7 - d1.get(Calendar.DAY_OF_WEEK);
		etmp = 7 - d2.get(Calendar.DAY_OF_WEEK);
		if (stmp != 0 && stmp != 6) {//开始日期为星期六和星期日时偏移量为0
			charge_start_date = stmp - 1;
		}
		if (etmp != 0 && etmp != 6) {//结束日期为星期六和星期日时偏移量为0
			charge_end_date = etmp - 1;
		}
		result = (getDaysBetween(getNextMonday(d1), getNextMonday(d2)) / 7)
				* 5 + charge_start_date - charge_end_date;
		return result;
	}

	/**
	 * @Desc 根据日期获知当天星期几
	 * @param date
	 * @return 返回中文星期几
	 */
	public static String getChineseWeek(Calendar date) {
		//1-星期日 2-星期一 3-星期二 4-星期三 5-星期四 6-星期五 7-星期六
		final String dayNames[] = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		int dayOfWeek = date.get(Calendar.DAY_OF_WEEK);
		return dayNames[dayOfWeek - 1];
	}

	/**
	 * @Desc 获得日期的下一个星期一的日期
	 * @param date
	 * @return
	 */
	public static Calendar getNextMonday(Calendar date) {
		Calendar result ;
		result = date;
		do {
			result = (Calendar) result.clone();
			result.add(Calendar.DATE, 1);
		} while (result.get(Calendar.DAY_OF_WEEK) != 2);
		return result;
	}

	/**
	 * @Desc 计算2个日期之间的休息日天数（只考虑周六周日不考虑节假日）
	 * @param d1 小日期
	 * @param d2 大日期
	 * @return
	 */
	public static int getOffDays(Calendar d1, Calendar d2){
		return getDaysBetween(d1, d2) - getWorkingDay(d1, d2);
	}

	/**
	 * @Desc 将日期时间中时间部分的:改成中文时分，最后加上秒
	 * @param dateTime 日期时间字符串
	 * @param h 时(点)
	 * @param m 分
	 * @param s 秒
	 * @return 返回结果比如：2017-07-05 11时28分06秒
	 */
	public static String convertDateTime2Zh(String dateTime, String h, String m, String s){
		StringBuilder stringBuilder = new StringBuilder();

		//方法一：str.replaceFirst(a, b)只将字符串str中第一次出现的字符串a替换为字符串b
		//dateTime = dateTime.replaceFirst(":", h);
		//dateTime = dateTime.replaceFirst(":", m);

		//方法二：StringUtils.replaceOnce(str, a, b)只将字符串str中第一次出现的字符串a替换为字符串b
		dateTime = StringUtils.replaceOnce(dateTime, ":", h);
		dateTime = StringUtils.replaceOnce(dateTime, ":", m);

		//2017-07-05 11时28分06秒
		return stringBuilder.append(dateTime).append(s).toString();
	}

	/**
	 * @Desc 计算两个日期相差多少天小时分钟
	 * @param endDate 结束日期
	 * @param startDate 开始日期
	 * @return 返回相差时间的拼接字符串，比如2,3,4表示相差2天3小时4分钟
	 */
	public static Long[] getDatePoor(Date endDate, Date startDate) {
		Long oneMinute = 1000 * 60L;//1分钟
		Long oneHour = 1000 * 60 * 60L;//1小时
		Long oneDay = 1000 * 24 * 60 * 60L;//1天
		Long interval = endDate.getTime() - startDate.getTime();//获得两个时间的毫秒时间差异
		Long day = interval / oneDay;//计算差多少天
		Long hour = interval % oneDay / oneHour;//计算差多少小时
		Long minute = interval % oneDay % oneHour / oneMinute;//计算差多少分钟
		return new Long[]{day, hour, minute};
	}

}
